package cc.verywell.pureblock.msg.nfs.linkmap;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;

import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.log.ThreadListener;
import cc.verywell.pureblock.msg.nfs.strc.EncodeAble;
import cc.verywell.pureblock.util.AutoClosed;

/**
* 
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年6月18日 上午9:24:08
*/
public class EasyTableHDhead implements ThreadListener,Comparable<EasyTableHDhead>,EncodeAble {

	final private int grade;
	final private long fileNumber;
	final private Path file;
	final LinkCell start,end;
	final private long fileSize;
	public EasyTableHDhead(int grade,long fileNumber,Path file, LinkCell start, LinkCell end) {
		this.grade = grade;
		this.fileNumber = fileNumber;
		this.file = file;
		this.start = start;
		this.end = end;
		try {
			this.fileSize = Files.size(file);
		} catch (IOException e) {
			throw new EasyIOException(e);
		}
	}
	public long getNumber() {
		return fileNumber;
	}
	public long fileSize() {
		return fileSize;
	}
	public int grade() {
		return grade;
	}
	public int startBetween(LinkCell startWith) {
		if(end.compareTo(startWith)<0)return 1;
		if(start.compareTo(startWith)<=0 || start.startWith(startWith))return 0;
		return -1;
	}
	public int between(LinkCell startWith) {
		if(start.compareTo(startWith)>0)return -1;
		if(end.compareTo(startWith)<0)return 1;
		return 0;
		//return start.compareTo(startWith)<=0 && end.compareTo(startWith)>=0;
	}
	public boolean overap(LinkCell start,LinkCell end) {
		if(start.compareTo(end)>0)return false;
		if(end.compareTo(start)<0)return false;
		return true;
	}
	@Override
	public int compareTo(EasyTableHDhead c) {
        if (this == c)return 0;
        int i = this.start.compareTo(c.start);
        if(i==0) {
        	return this.end.compareTo(c.end);
        }
        return i;
	}
	
	@Override
	public void threadWait() {
		if(Pblog.DEBUG)Pblog.DEBUG("talbeHD ",file," readstart");
	}
	@Override
	public void threadWake() {
		if(Pblog.DEBUG)Pblog.DEBUG("talbeHD ",file," readend");
	}
	@Override
	public void threadIn() {
		if(Pblog.DEBUG)Pblog.DEBUG("talbeHD ",file," opened");
	}
	@Override
	public void threadOut() {
		if(Pblog.DEBUG)Pblog.DEBUG("talbeHD ",file," closed");
	}
	
	private WeakReference<EasyTable> hd;
	public EasyTable getTable(AutoClosed ac) {
		synchronized (this) {
			EasyTable table = hd!=null?hd.get():null;
			if(table!=null)return table;
			
			try {
				EasyTableHD hd = new EasyTableHD(file, this);
				ac.add(hd, hd.autoClose());
				table = hd;
			} catch (IOException e) {
				if(EasyFileController.IGNORE_FILE_MISS) {
					if(Pblog.IO)Pblog.IO("ignore easyTable err ",file," ",e);
					table = EMPTY_TABLE;
				}else {
					throw new EasyIOException(e);
				}
			}
			
			this.hd = new WeakReference<EasyTable>(table);
			return table;
					
		}
	}
	
	final static private EasyTable EMPTY_TABLE = new EasyTable() {
		@Override
		public EasyIterator get(LinkCell startWith) {
			return null;
		}
	};
	
	
	@Override
	public void encode(ByteBuffer bb) {
		LinkCell.lengthEncodeInt(bb, grade);
		LinkCell.lengthEncodeLong(bb, fileNumber);
		LinkCell.lengthEncodeInt(bb, start.encodeSize());
		start.encode(bb);
		LinkCell.lengthEncodeInt(bb, end.encodeSize());
		end.encode(bb);
	}
	@Override
	public int encodeSize() {
		return LinkCell.lengthSize(grade)+LinkCell.lengthSize(fileNumber)+
				LinkCell.lengthSize(start.encodeSize())+start.encodeSize()+
				LinkCell.lengthSize(end.encodeSize())+end.encodeSize()
				;
	}
	static public EasyTableHDhead decode(ByteBuffer bb,EasyFileController clr) {
		int grade = LinkCell.lengthDecodeInt(bb);
		long fileNumber = LinkCell.lengthDecodeLong(bb);
		int size = LinkCell.lengthDecodeInt(bb);
		byte[] sb = new byte[size];
		bb.get(sb);
		size = LinkCell.lengthDecodeInt(bb);
		byte[] eb = new byte[size];
		bb.get(eb);
		return new EasyTableHDhead(grade,fileNumber,clr.getHDfile(fileNumber),new LinkCell(sb),new LinkCell(eb));
	}
	
	public EasyTableHDhead clone(int grade) {
		return new EasyTableHDhead(grade,this.fileNumber, this.file, this.start, this.end);
	}

}
